//
// Created by yyl on 2018/6/6.
//

#include "CallJava.h"

CallJava::CallJava(JNIEnv *env, jobject player) {
    this->jniEnv = env;
    this->yPlayer = player;
    jint result = env->GetJavaVM(&this->javaVM);
    if (result != 0) {
        LOGE("javaVM  CallJava  error");
    }
    jclass clazz = jniEnv->GetObjectClass(player);
    if (!clazz) {
        LOGE("GetMethodID  onJNICallBackEvent  error");
        return;
    }
    this->javaOnCallBackEvent = jniEnv->GetMethodID(clazz,
                                                    "onJNICallBackEvent",
                                                    "(III)V");
    this->javaOnCallPcmToAAC = jniEnv->GetMethodID(clazz,
                                                   "onJNICallPcmToAAC",
                                                   "(II[B)V");
    this->javaOnCallRenderYUV = jniEnv->GetMethodID(clazz,
                                                    "onJNICallRenderYUV",
                                                    "(II[B[B[B)V");
    this->javaOnCallSupportHardware = jniEnv->GetMethodID(clazz,
                                                          "onJNISupportHardware",
                                                          "(Ljava/lang/String;)Z");
    this->javaOnCallInitMediaCodec = jniEnv->GetMethodID(clazz,
                                                         "onJNIInitMediaCodec",
                                                         "(Ljava/lang/String;II[B[B)Z");
    this->javaOnCalldecodeAVPacket = jniEnv->GetMethodID(clazz,
                                                         "onJNIdecodeAVPacket",
                                                         "(I[B)V");


}

void CallJava::onCallBackEvent(int threadType, int event, int arg1, int arg2) {

    if (threadType == THREAD_MAIN) {//主线程
        jniEnv->CallVoidMethod(yPlayer, javaOnCallBackEvent, event, arg1, arg2);
    } else if (threadType == THREAD_CHILD) {
        //子线程
        JNIEnv *jniEnv;
        if (javaVM->AttachCurrentThread(&jniEnv, 0) != JNI_OK) {
            LOGE("call onCallBackEvent  wrong")
            return;
        }
        jniEnv->CallVoidMethod(yPlayer, javaOnCallBackEvent, event, arg1, arg2);
        javaVM->DetachCurrentThread();
    }
}

CallJava::~CallJava() {

}

void CallJava::onCallPcmToAAC(int threadType, int event, int size, void *buffer) {
    if (threadType == THREAD_MAIN) {//主线程
        jbyteArray jbuffer = jniEnv->NewByteArray(size);
        jniEnv->SetByteArrayRegion(jbuffer, 0, size, static_cast<const jbyte *>(buffer));
        jniEnv->CallVoidMethod(yPlayer, javaOnCallPcmToAAC, event, size, buffer);
        jniEnv->DeleteLocalRef(jbuffer);
    } else if (threadType == THREAD_CHILD) {
        //子线程
        JNIEnv *jniEnv;
        if (javaVM->AttachCurrentThread(&jniEnv, 0) != JNI_OK) {
            LOGE("call onCallPcmToAAC  wrong")
            return;
        }
        jbyteArray jbuffer = jniEnv->NewByteArray(size);
        jniEnv->SetByteArrayRegion(jbuffer, 0, size, static_cast<const jbyte *>(buffer));
        jniEnv->CallVoidMethod(yPlayer, javaOnCallPcmToAAC, event, size, jbuffer);
        jniEnv->DeleteLocalRef(jbuffer);
        javaVM->DetachCurrentThread();
    }
}

void
CallJava::onCallRenderYUV(int width, int height, uint8_t *frameY, uint8_t *frameU,
                          uint8_t *frameV) {
//子线程
    JNIEnv *jniEnv;
    if (javaVM->AttachCurrentThread(&jniEnv, 0) != JNI_OK) {
        LOGE("call onCallRenderYUV  wrong")
        return;
    }
    jbyteArray y = jniEnv->NewByteArray(width * height);
    jniEnv->SetByteArrayRegion(y, 0, width * height, reinterpret_cast<const jbyte *>(frameY));
    jbyteArray u = jniEnv->NewByteArray(width * height / 4);
    jniEnv->SetByteArrayRegion(u, 0, width * height / 4, reinterpret_cast<const jbyte *>(frameU));
    jbyteArray v = jniEnv->NewByteArray(width * height / 4);
    jniEnv->SetByteArrayRegion(v, 0, width * height / 4, reinterpret_cast<const jbyte *>(frameV));

    jniEnv->CallVoidMethod(yPlayer, javaOnCallRenderYUV, width, height, y, u, v);
    jniEnv->DeleteLocalRef(y);
    jniEnv->DeleteLocalRef(u);
    jniEnv->DeleteLocalRef(v);
    javaVM->DetachCurrentThread();
}

bool CallJava::onCallIsSupportHardware(const char *ffcodecName) {
    //子线程
    bool support = false;
    JNIEnv *jniEnv;
    if (javaVM->AttachCurrentThread(&jniEnv, 0) != JNI_OK) {
        LOGE("call onCallIsSupportHardware  wrong")
        return support;
    }
    jstring type = jniEnv->NewStringUTF(ffcodecName);
    support = jniEnv->CallBooleanMethod(yPlayer, javaOnCallSupportHardware, type);
    jniEnv->DeleteLocalRef(type);
    javaVM->DetachCurrentThread();
    return support;
}

bool CallJava::onCallInitMediacodec(const char *mimeType, int width, int height, int csd0_size,
                                    int csd1_size, uint8_t *csd_0, uint8_t *csd_1) {
    bool support = false;
    JNIEnv *jniEnv;
    if (javaVM->AttachCurrentThread(&jniEnv, 0) != JNI_OK) {
        LOGE("call onCallInitMediacodec  wrong")
        return support;
    }
    jstring type = jniEnv->NewStringUTF(mimeType);
    jbyteArray csd0 = jniEnv->NewByteArray(csd0_size);
    jniEnv->SetByteArrayRegion(csd0, 0, csd0_size, reinterpret_cast<const jbyte *>(csd_0));
    jbyteArray csd1 = jniEnv->NewByteArray(csd1_size);
    jniEnv->SetByteArrayRegion(csd1, 0, csd1_size, reinterpret_cast<const jbyte *>(csd_1));

    support = jniEnv->CallBooleanMethod(yPlayer, javaOnCallInitMediaCodec, type, width, height,
                                        csd0, csd1);

    jniEnv->DeleteLocalRef(csd0);
    jniEnv->DeleteLocalRef(csd1);
    jniEnv->DeleteLocalRef(type);
    javaVM->DetachCurrentThread();
    return support;
}

void CallJava::onCallDecodeAVPacket(int datasize, uint8_t *packetdata) {
    JNIEnv *jniEnv;
    if (javaVM->AttachCurrentThread(&jniEnv, 0) != JNI_OK) {
        LOGE("call onCallDecodeAVPacket  wrong")
        return;
    }
    jbyteArray data = jniEnv->NewByteArray(datasize);
    jniEnv->SetByteArrayRegion(data, 0, datasize, reinterpret_cast<const jbyte *>(packetdata));
    jniEnv->CallVoidMethod(yPlayer, javaOnCalldecodeAVPacket, datasize, data);
    jniEnv->DeleteLocalRef(data);
    javaVM->DetachCurrentThread();
}
